﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Application.Core.Entities;
using NPoco;
using NPoco.Expressions;
using NPoco.Linq;

namespace Application.Core.Interfaces
{
    /// <summary>
    /// 仓储接口
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public interface IRepository<TEntity> where TEntity : BaseEntity
    {
        IDatabase DbContext { get; set; }

        /// <summary>
        /// 把实体entity添加到数据库
        /// 
        /// </summary>
        /// <param name="entity">实体</param>
        object Insert(TEntity entity);

        /// <summary>
        /// 异步插入实体
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns>主键</returns>
        Task<object> InsertAsync(TEntity entity);

        /// <summary>
        /// 把实体entiy更新到数据库
        /// 
        /// </summary>
        /// <param name="entity">实体</param>
        void Update(TEntity entity);

        /// <summary>
        /// 异步更新实体
        /// </summary>
        /// <param name="entity">实体对象</param>
        Task<int> UpdateAsync(TEntity entity);

        /// <summary>
        /// 根据主键删除
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>删除的数量</returns>
        int Delete(object primaryKey);

        /// <summary>
        /// 从数据库删除实体
        /// 
        /// </summary>
        /// <param name="entity">实体</param>
        /// <returns/>
        int Delete(TEntity entity);

        /// <summary>
        /// 异步根据实体删除
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns>删除的数量</returns>
        Task<int> DeleteAsync(TEntity entity);

        /// <summary>
        /// 根据主键判断是否存在
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns></returns>
        bool Exists(object primaryKey);

        /// <summary>
        /// 获取单条
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>实体对象</returns>
        TEntity Single(object primaryKey);

        /// <summary>
        /// 异步获取单条
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>实体对象</returns>
        Task<TEntity> SingleAsync(object primaryKey);

        /// <summary>
        /// 获取单条或默认第一条
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>实体对象</returns>
        TEntity SingleOrDefault(object primaryKey);

        /// <summary>
        /// 异步获取单条或默认第一条
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>实体对象</returns>
        Task<TEntity> SingleOrDefaultAsync(object primaryKey);

        /// <summary>
        /// 获取所有的数据，仅用于数据量非常少的情况下
        /// </summary>
        /// <returns>实体集合</returns>
        IEnumerable<TEntity> GetAll();

        /// <summary>
        /// 异步获取所有的数据，仅用于数据量非常少的情况下
        /// </summary>
        /// <returns>实体集合</returns>
        Task<IEnumerable<TEntity>> GetAllAsync();

        /// <summary>
        /// 获取所有的数据并排序，仅用于数据量非常少的情况下
        /// </summary>
        /// <param name="orderBy">排序条件</param>
        /// <returns>实体集合</returns>
        IEnumerable<TEntity> GetAll(string orderBy);

        /// <summary>
        /// 异步获取所有的数据并排序，仅用于数据量非常少的情况下
        /// </summary>
        /// <param name="orderBy">排序条件</param>
        /// <returns>实体集合</returns>
        Task<IEnumerable<TEntity>> GetAllAsync(string orderBy);

        /// <summary>
        /// 获取指定的前某条数据
        /// </summary>
        /// <param name="topNumber">数量</param>
        /// <returns>实体集合</returns>
        IEnumerable<TEntity> GetTop(int topNumber);

        /// <summary>
        /// 异步获取指定的前某条数据
        /// </summary>
        /// <param name="topNumber">数量</param>
        /// <returns>实体集合</returns>
        Task<IEnumerable<TEntity>> GetTopAsync(int topNumber);

        /// <summary>
        /// 获取排序后的指定前某条数据
        /// </summary>
        /// <param name="topNumber">数量</param>
        /// <param name="orderBy">排序条件</param>
        /// <returns>实体集合</returns>
        IEnumerable<TEntity> GetTop(int topNumber, string orderBy);

        /// <summary>
        /// 异步获取排序后的指定前某条数据
        /// </summary>
        /// <param name="topNumber">数量</param>
        /// <param name="orderBy">排序条件</param>
        /// <returns>实体集合</returns>
        Task<IEnumerable<TEntity>> GetTopAsync(int topNumber, string orderBy);

        /// <summary>
        /// 分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <returns>分页数据对象</returns>
        Page<TEntity> GetPage(long pageIndex, long pageSize);

        /// <summary>
        /// 异步分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <returns>分页数据对象</returns>
        Task<Page<TEntity>> GetPageAsync(long pageIndex, long pageSize);

        /// <summary>
        /// 分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="orderBy">排序条件</param>
        /// <returns>分页数据对象</returns>
        Page<TEntity> GetPage(long pageIndex, long pageSize, string orderBy);

        /// <summary>
        /// 异步分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="orderBy">排序条件</param>
        /// <returns>分页数据对象</returns>
        Task<Page<TEntity>> GetPageAsync(long pageIndex, long pageSize, string orderBy);

        /// <summary>
        /// 分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="sql"></param>
        /// <returns>分页数据对象</returns>
        Page<TEntity> GetPage(long pageIndex, long pageSize, Sql sql);

        /// <summary>
        /// 异步分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="sql"></param>
        /// <returns>分页数据对象</returns>
        Task<Page<TEntity>> GetPageAsync(long pageIndex, long pageSize, Sql sql);

        /// <summary>
        /// 依据EntityId集合组装成实体集合（自动缓存）
        /// 
        /// </summary>
        /// <param name="entityIds">主键集合</param>
        IEnumerable<TEntity> GetByIds<T>(IEnumerable<T> entityIds);

        /// <summary>
        /// 异步根据主键的数组查询
        /// </summary>
        /// <typeparam name="T">主键类型</typeparam>
        /// <param name="entityIds">主键数组</param>
        /// <returns>实体集合</returns>
        Task<IEnumerable<TEntity>> GetByIdsAsync<T>(IEnumerable<T> entityIds);

        /// <summary>
        /// 通用查询接口
        /// </summary>
        /// <typeparam name="TEntity">类型</typeparam>
        /// <param name="sql">SQL查询对象</param>
        /// <returns>实体集合</returns>
        IEnumerable<TEntity> Query(Sql sql);

        /// <summary>
        /// 异步通用查询接口
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="sql">SQL查询对象</param>
        /// <returns>实体集合</returns>
        Task<IEnumerable<TEntity>> QueryAsync(Sql sql);

        /// <summary>
        /// Linq多条删除
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <returns>删除的Linq查询</returns>
        IDeleteQueryProvider<TEntity> DeleteMany();

        /// <summary>
        /// Linq多条更新
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <returns>更新的Linq查询</returns>
        IUpdateQueryProvider<TEntity> UpdateMany();

        /// <summary>
        /// Linq延迟查询
        /// </summary>
        /// <typeparam name="TEntity">类型</typeparam>
        /// <returns>Linq查询</returns>
        IQueryProviderWithIncludes<TEntity> Query();
    }
}
